import java.util.*;

/**
 * Created by L.jp
 * Description:链接：https://www.nowcoder.com/questionTerminal/67df1d7889cf4c529576383c2e647c48
 * 来源：牛客网
 *
 * 开发一个简单错误记录功能小模块，能够记录出错的代码所在的文件名称和行号。
 * 处理:
 * 1.记录最多8条错误记录，对相同的错误记录(即文件名称和行号完全匹配)只记录一条，错误计数增加；(文件所在的目录不同，文件名和行号相同也要合并)
 * 2.超过16个字符的文件名称，只记录文件的最后有效16个字符；(如果文件名不同，而只是文件名的后16个字符和行号相同，也不要合并)
 * 3.输入的文件可能带路径，记录文件名称不能带路径
 *
 * 数据范围：输入错误记录数量满足 1 \le n \le 1000 \1≤n≤1000  ，每条记录的长度满足 1 \le len \le 50 \1≤len≤50
 *
 * 输入描述:
 * 一行或多行字符串。每行包括带路径文件名称，行号，以空格隔开。
 *
 *     文件路径为windows格式
 *
 *     如：E:\V1R2\product\fpgadrive.c 1325
 *
 *
 * 输出描述:
 * 将所有的记录统计并将结果输出，格式：文件名代码行数数目，一个空格隔开，如: fpgadrive.c 1325 1
 *
 *     结果根据数目从多到少排序，数目相同的情况下，按照输入第一次出现顺序排序。
 *
 *     如果超过8条记录，则只输出前8条记录.
 *
 *     如果文件名的长度超过16个字符，则只输出后16个字符
 * User: 86189
 * Date: 2022-04-23
 * Time: 11:07
 */
public class Main2 {
    //这个题也是一个简单错误记录，但是记录错误的方法不一样
    //关键信息：
    // 1.记录最多8条错误记录，对相同的错误记录(即文件名称和行号完全匹配)只记录一条，错误计数增加；(文件所在的目录不同，文件名和行号相同也要合并)
    // 2.超过16个字符的文件名称，只记录文件的最后有效16个字符；(如果文件名不同，而只是文件名的后16个字符和行号相同，也不要合并)
    // 3.结果根据数目从多到少排序，数目相同的情况下，按照输入第一次出现顺序排序。
    // 4.如果超过8条记录，则只输出前8条记录.
    // 也就是说只有文件名完全相同才算匹配，文件名的后16个字符匹配不算匹配
    public static void main(String[] args){
        Scanner scan=new Scanner(System.in);
        //因为要求要按文件的错误次数由多到少排序，但是顺序表只是可以按照出现的顺序来排序，因为这里我们的顺序表是用来存储字符串的，不用来存储错误次数
        //必须使用哈希表来存储文件字符串和行号。以及错误的次数，但是普通的hashmap是没有顺序的，所以我们可以采用LinkedHashmap,保证是按输入的顺序存储的
        Map<String,Integer> map=new LinkedHashMap<>();
        while (scan.hasNext()){
            //先输入可能带路径文件
            String filePath=scan.next();
            String row=scan.next();
            //找到最后一个\的位置
            int index=filePath.lastIndexOf("\\");
            //由于文件可能是带路径的也有可能是不带路径的，如果不带路径，那么这个文件本身就可以是文件名，如果带了路径那么就需要找到最后一个\后面的作为文件名
            String file=index==-1 ?  filePath: filePath.substring(index + 1) ;
            String str=file+" "+row;
            //放入哈希表
            if(!map.containsKey(str)){
                map.put(str,1);
            }else{
                map.put(str,map.get(str)+1);
            }
        }
        //接着是输出，要按照错误次数的从大到小输出，但是map不具有排序的功能，所以需要借助list
        ////将map集合变成list，方便对map的value进行排序
        //Map.Entry是将map放入list之后每个元素的类型，map.entrySet是list的每一个元素
        List<Map.Entry<String, Integer>> ret=new LinkedList<>(map.entrySet());
        //对象的sort对list里的元素按照错误次数的从大到小排序,需要实现compare方法
        ret.sort(new Comparator<Map.Entry<String, Integer>>() {
            @Override
            //实现一个降序比较规则，默认是一个升序
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o2.getValue() - o1.getValue(); //改为降序
            }
        });
        int i=0;
        for(Map.Entry<String,Integer> m:ret){
            if(i>=8){
                break; //超过了8次，直接停输出
            }
            //去除文件名和行号构成的字符串也就是key的值
            String[] key=m.getKey().split(" ");
            //拿到文件名，以便后序打印
            String f=key[0];
            //只取后16位
            if(f.length()>16){
                f=f.substring(f.length()-16);
            }
            String rowStr=key[1];
            //错误次数
            int count=m.getValue();
            System.out.println(f+" "+rowStr+" "+count);
            i++;
        }
    }
}
